package com.zdkj.subway.rca.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdkj.common.core.exceltools.MultipartFileToFile;
import com.zdkj.common.core.util.R;
import com.zdkj.subway.rca.entity.SwCkDataauditAccinvest;
import com.zdkj.subway.rca.mapper.SwCkDataauditAccinvestMapper;
import com.zdkj.subway.rca.service.SwCkDataauditAccinvestService;
import com.zdkj.subway.rca.util.LocalDateConverter;
import com.zdkj.subway.rca.util.LocalDateTimeConverter;
import com.zdkj.subway.rca.util.MyDateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author lu
 * @Date 2021-09-08
 */
@Service
public class SwCkDataauditAccinvestServiceImpl extends ServiceImpl<SwCkDataauditAccinvestMapper, SwCkDataauditAccinvest> implements SwCkDataauditAccinvestService{
    private static final Logger LOGGER = LoggerFactory.getLogger(SwCkDataauditAccinvestServiceImpl.class);
    @Resource
    private SwCkDataauditAccinvestMapper swCkDataauditAccinvestMapper;

    /**
     * 生成差异报表
     * @param startDate
     * @param endDate
     */
    @Override
    public void generateDifferenceReport(String startDate, String endDate) {
        List<SwCkDataauditAccinvest> oldList = new ArrayList<>();
        List<SwCkDataauditAccinvest> newList = new ArrayList<>();
        //bom-acc-合并
        List<SwCkDataauditAccinvest> accAllList = swCkDataauditAccinvestMapper.getAccAllList(startDate,endDate);
        if(CollectionUtils.isNotEmpty(accAllList)){
            oldList.addAll(accAllList);
        }
//        //bom-acc-支付宝
//        List<SwCkDataauditAccinvest> bomToAccToAlipayList = swCkDataauditAccinvestMapper.getBomToAccToAlipay(startDate,endDate);
//        if(CollectionUtil.isNotEmpty(bomToAccToAlipayList)){
//            oldList.addAll(bomToAccToAlipayList);
//        }
//        //bom-acc-微信
//        List<SwCkDataauditAccinvest> bomToAccToWeChatList = swCkDataauditAccinvestMapper.getBomToAccToWeChat(startDate,endDate);
//        if(CollectionUtil.isNotEmpty(bomToAccToWeChatList)){
//            oldList.addAll(bomToAccToWeChatList);
//        }
        //bom-平台-支付宝
        List<SwCkDataauditAccinvest> bomToTerraceToAlipayList = swCkDataauditAccinvestMapper.getBomToTerraceToAlipay(startDate,endDate);
        if(CollectionUtil.isNotEmpty(bomToTerraceToAlipayList)){
            oldList.addAll(bomToTerraceToAlipayList);
        }
        //bom-平台-微信
        List<SwCkDataauditAccinvest> bomToTerraceToWeChatList = swCkDataauditAccinvestMapper.getBomToTerraceToWeChat(startDate,endDate);
        if(CollectionUtil.isNotEmpty(bomToTerraceToWeChatList)){
            oldList.addAll(bomToTerraceToWeChatList);
        }

//        //tvm-acc-支付宝
//        List<SwCkDataauditAccinvest> tvmToAccToAlipayList = swCkDataauditAccinvestMapper.getTvmToAccToAlipay(startDate,endDate);
//        if(CollectionUtil.isNotEmpty(tvmToAccToAlipayList)){
//            oldList.addAll(tvmToAccToAlipayList);
//        }
//        //tvm-acc-微信
//        List<SwCkDataauditAccinvest> tvmToAccToWeChatList = swCkDataauditAccinvestMapper.getTvmToAccToWeChat(startDate,endDate);
//        if(CollectionUtil.isNotEmpty(tvmToAccToWeChatList)){
//            oldList.addAll(tvmToAccToWeChatList);
//        }
//        //tvm-acc-银联
//        List<SwCkDataauditAccinvest> tvmToAccToUnionPayList = swCkDataauditAccinvestMapper.getTvmToAccToUnionPay(startDate,endDate);
//        if(CollectionUtil.isNotEmpty(tvmToAccToUnionPayList)){
//            oldList.addAll(tvmToAccToUnionPayList);
//        }
        //tvm-平台-支付宝-微信-银联
        List<SwCkDataauditAccinvest> tvmToTerraceToMergeList = swCkDataauditAccinvestMapper.getTvmToTerraceToMerge(startDate,endDate);
        if(CollectionUtil.isNotEmpty(tvmToTerraceToMergeList)){
            oldList.addAll(tvmToTerraceToMergeList);
        }

        if(CollectionUtil.isNotEmpty(oldList)){
            //分组处理
            Map<String, List<SwCkDataauditAccinvest>> collectMap = oldList.stream().collect(Collectors.groupingBy(swKey -> swKey.getTradeDate() + "_" + swKey.getLineCode() + "_" + swKey.getStationCode()));
            Set<String> keySet = collectMap.keySet();
            for (String key : keySet) {
                List<SwCkDataauditAccinvest> swCkDataauditAccinvests = collectMap.get(key);
                if(CollectionUtil.isNotEmpty(swCkDataauditAccinvests)){
                    SwCkDataauditAccinvest swCkDataauditAccinvest = new SwCkDataauditAccinvest();
                    String[] split = key.split("_");
                    LocalDate tradeDate = MyDateUtil.StringTurnLocalDate(split[0]);
                    String lineCode = split[1];
                    String stationCode = split[2];

                    swCkDataauditAccinvest.setTradeDate(tradeDate);
                    swCkDataauditAccinvest.setLineCode(lineCode);
                    swCkDataauditAccinvest.setStationCode(stationCode);


                    for (SwCkDataauditAccinvest accinvest : swCkDataauditAccinvests) {
                        swCkDataauditAccinvest.setBomMoneyAccAlipy(ifNullDecimal(swCkDataauditAccinvest.getBomMoneyAccAlipy()).add(ifNullDecimal(accinvest.getBomMoneyAccAlipy())));
                        swCkDataauditAccinvest.setBomMoneyAccWechat(ifNullDecimal(swCkDataauditAccinvest.getBomMoneyAccWechat()).add(ifNullDecimal(accinvest.getBomMoneyAccWechat())));
                        swCkDataauditAccinvest.setBomMoneyPlatAlipy(ifNullDecimal(swCkDataauditAccinvest.getBomMoneyPlatAlipy()).add(ifNullDecimal(accinvest.getBomMoneyPlatAlipy())));
                        swCkDataauditAccinvest.setBomMoneyPlatWechat(ifNullDecimal(swCkDataauditAccinvest.getBomMoneyPlatWechat()).add(ifNullDecimal(accinvest.getBomMoneyPlatWechat())));

                        swCkDataauditAccinvest.setTvmMoneyAccAlipy(ifNullDecimal(swCkDataauditAccinvest.getTvmMoneyAccAlipy()).add(ifNullDecimal(accinvest.getTvmMoneyAccAlipy())));
                        swCkDataauditAccinvest.setTvmMoneyAccWechat(ifNullDecimal(swCkDataauditAccinvest.getTvmMoneyAccWechat()).add(ifNullDecimal(accinvest.getTvmMoneyAccWechat())));
                        swCkDataauditAccinvest.setTvmMoneyAccUnion(ifNullDecimal(swCkDataauditAccinvest.getTvmMoneyAccUnion()).add(ifNullDecimal(accinvest.getTvmMoneyAccUnion())));
                        swCkDataauditAccinvest.setTvmMoneyPlatAlipy(ifNullDecimal(swCkDataauditAccinvest.getTvmMoneyPlatAlipy()).add(ifNullDecimal(accinvest.getTvmMoneyPlatAlipy())));
                        swCkDataauditAccinvest.setTvmMoneyPlatWechat(ifNullDecimal(swCkDataauditAccinvest.getTvmMoneyPlatWechat()).add(ifNullDecimal(accinvest.getTvmMoneyPlatWechat())));
                        swCkDataauditAccinvest.setTvmMoneyPlatUnion(ifNullDecimal(swCkDataauditAccinvest.getTvmMoneyPlatUnion()).add(ifNullDecimal(accinvest.getTvmMoneyPlatUnion())));
                    }
                    //计算差异
                    swCkDataauditAccinvest.setBomMoneyDiffAlipy(swCkDataauditAccinvest.getBomMoneyAccAlipy().subtract(swCkDataauditAccinvest.getBomMoneyPlatAlipy()));
                    swCkDataauditAccinvest.setBomMoneyDiffWechat(swCkDataauditAccinvest.getBomMoneyAccWechat().subtract(swCkDataauditAccinvest.getBomMoneyPlatWechat()));
                    swCkDataauditAccinvest.setTvmMoneyDiffAlipy(swCkDataauditAccinvest.getTvmMoneyAccAlipy().subtract(swCkDataauditAccinvest.getTvmMoneyPlatAlipy()));
                    swCkDataauditAccinvest.setTvmMoneyDiffWechat(swCkDataauditAccinvest.getTvmMoneyAccWechat().subtract(swCkDataauditAccinvest.getTvmMoneyPlatWechat()));
                    swCkDataauditAccinvest.setTvmMoneyDiffUnion(swCkDataauditAccinvest.getTvmMoneyAccUnion().subtract(swCkDataauditAccinvest.getTvmMoneyPlatUnion()));
                    newList.add(swCkDataauditAccinvest);
                }
            }
        }
        if(CollectionUtil.isNotEmpty(newList)){
            //TODO  根据线路+站点+日期判断是否存在，如果存在更新，不存在插入
            // 覆盖导入不会覆盖掉之前回复过的原因和日期，是否处理
            LambdaQueryWrapper<SwCkDataauditAccinvest> wrapper =
                    Wrappers.<SwCkDataauditAccinvest>lambdaQuery().between(SwCkDataauditAccinvest::getTradeDate,
                            startDate, endDate);
            List<SwCkDataauditAccinvest> list = this.list(wrapper);
            List<SwCkDataauditAccinvest> collect = newList.stream().map(m -> {
                list.stream().filter(m2 -> m.getTradeDate().equals(m2.getTradeDate()) && m.getLineCode().equals(m2.getLineCode()) && m.getStationCode().equals(m2.getStationCode()))
                        .forEach(s -> m.setId(s.getId()));
                return m;
            }).collect(Collectors.toList());

            this.saveOrUpdateBatch(collect);
        }
    }

    /**
     * 导出
     * @param startDate
     * @param endDate
     * @param lineCode
     * @param stationCode
     * @param startReplyDate
     * @param endReplyDate
     * @param response
     */
    @Override
    public void export(String startDate, String endDate, String lineCode, String stationCode, String startReplyDate, String endReplyDate, HttpServletResponse response) {

        List<SwCkDataauditAccinvest> records = this.baseMapper.getList(startDate,endDate,lineCode,stationCode,startReplyDate,endReplyDate);
        BigDecimal decimal100 = new BigDecimal("100");
        if(CollectionUtil.isNotEmpty(records)){
            for (SwCkDataauditAccinvest record : records) {
                record.setBomMoneyAccAlipy(record.getBomMoneyAccAlipy().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setBomMoneyAccWechat(record.getBomMoneyAccWechat().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setBomMoneyPlatAlipy(record.getBomMoneyPlatAlipy().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setBomMoneyPlatWechat(record.getBomMoneyPlatWechat().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setBomMoneyDiffAlipy(record.getBomMoneyDiffAlipy().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setBomMoneyDiffWechat(record.getBomMoneyDiffWechat().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));

                record.setTvmMoneyAccAlipy(record.getTvmMoneyAccAlipy().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setTvmMoneyAccWechat(record.getTvmMoneyAccWechat().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setTvmMoneyAccUnion(record.getTvmMoneyAccUnion().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setTvmMoneyPlatAlipy(record.getTvmMoneyPlatAlipy().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setTvmMoneyPlatWechat(record.getTvmMoneyPlatWechat().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setTvmMoneyPlatUnion(record.getTvmMoneyPlatUnion().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setTvmMoneyDiffAlipy(record.getTvmMoneyDiffAlipy().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setTvmMoneyDiffWechat(record.getTvmMoneyDiffWechat().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
                record.setTvmMoneyDiffUnion(record.getTvmMoneyDiffUnion().divide(decimal100,2,BigDecimal.ROUND_HALF_UP));
            }
            InputStream excelTemplateIs = null;
            try {
                response.reset(); // 非常重要
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
                final String fileName = URLEncoder.encode("acc充值和平台差异表", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xlsx");

                // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
                // {} 代表普通变量 {.} 代表是list的变量
                excelTemplateIs = this.getClass().getResourceAsStream("/static/excel/template/export/SwCkDataauditAccinvestExcelTemplate.xlsx");

                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerConverter(new LocalDateTimeConverter()).registerConverter(new LocalDateConverter()).withTemplate(excelTemplateIs).build();
                WriteSheet writeSheet = EasyExcel.writerSheet("acc充值和平台差异表").build();
                // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行，然后下面的数据往后移动。默认 是false，会直接使用下一行，如果没有则创建。
                // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了，所以慎用
                // 简单的说 如果你的模板有list,且list不是最后一行，下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
                // 如果数据量大 list不是最后一行 参照另一个
                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.FALSE).build();
                excelWriter.fill(records, fillConfig, writeSheet);
                excelWriter.finish();

            } catch (Exception e) {
                e.printStackTrace();
                LOGGER.error("导出acc充值和平台差异表异常");
            } finally {
                if(excelTemplateIs != null){
                    try {
                        excelTemplateIs.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 导入
     * @param file
     * @throws Exception
     */
    @Override
    public R importAccInvest(MultipartFile file) throws Exception{
        final File excelFile = MultipartFileToFile.multipartFileToFile(file);
        List<Map<Integer, String>> listMap = EasyExcel.read(excelFile).sheet().headRowNumber(4).doReadSync();
        if (CollectionUtil.isNotEmpty(listMap)) {
            List<SwCkDataauditAccinvest> accinvestList = new ArrayList<>();
            MultipartFileToFile.delteTempFile(excelFile);
            for (int m = 0; m < listMap.size(); m++) {
                Map<Integer, String> data = listMap.get(m);
                LOGGER.info("读取到数据:{}", JSON.toJSONString(data));
                //回复原因或者时间不是null的时候才修改
                if(ObjectUtil.isNotEmpty(data.get(19)) || ObjectUtil.isNotEmpty(data.get(20))){
                    SwCkDataauditAccinvest accinvest = new SwCkDataauditAccinvest();
                    accinvest.setId(new Double(Double.parseDouble(data.get(0))).longValue());//ID
                    if(ObjectUtil.isNotEmpty(data.get(19))){
                        accinvest.setReplyReason(data.get(19));
                    }
                    if(ObjectUtil.isNotEmpty(data.get(20))){
                        //excel导入的日期格式2021-09-09
                        boolean date = MyDateUtil.isDate(data.get(20), "yyyy-MM-dd");
                        if(!date){
                            return R.failed("请检查 第" + (m+5) +"行 回复时间格式是否正确！");
                        }
                        accinvest.setReplyDate(MyDateUtil.StringTurnLocalDate(data.get(20)));
                    }
                    accinvestList.add(accinvest);
                }

            }
            //  增加根据id批量更新回馈信息方法
            if(CollectionUtils.isNotEmpty(accinvestList)){
                this.updateBatchById(accinvestList);
            }
        }
        return R.ok();
    }

    /**
     * 校验null
     * @param amount
     * @return
     */
    private BigDecimal ifNullDecimal(BigDecimal amount) {
        if(amount == null){
            return new BigDecimal("0");
        }
        return amount;
    }
}
